package com.xdy.secret.algorithm;

import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import org.apache.commons.io.FileUtils;

import javax.crypto.Cipher;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * @Author: XDY.
 * @Email: 2280944114@qq.com
 * @CreateTime: 2023-09-05  23:07
 * @Description: 非对称加密算法 RSA
 * @Version: 1.0
 */
public class RSADemo {
    public static void main(String[] args) throws Exception {
        //原文
        String input = "许琳康";
        //创建密钥对
        //对称加密算法
        String algorithm = "RSA";

        String pubPath = "a.pub";
        String priPath = "a.pri";

        //生成密钥对并保存在本地文件中
        generateKeyToFile(algorithm,pubPath,priPath);

        //获取密钥对生成对象
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        //生成密钥对对象
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        //生成公钥和私钥
        //公钥
        PublicKey publicKey = keyPair.getPublic();
        //私钥
        PrivateKey privateKey = keyPair.getPrivate();
        //获取公钥的字节数组
        byte[] publicKeyEncoded = publicKey.getEncoded();
        //获取私钥的字节数组
        byte[] privateKeyEncoded = privateKey.getEncoded();
        String publicEncode = Base64.encode(publicKeyEncoded);
        System.out.println("publicEncode = " + publicEncode);
        String privateEncode = Base64.encode(privateKeyEncoded);
        System.out.println("privateEncode = " + privateEncode);

        //使用公钥加密
        String encode = encodeRSA(algorithm, publicKey, input);
        System.out.println("公钥加密后 = " + encode);
        //使用私钥解密
        System.out.println("私钥解密 = " + decodeRSA(algorithm,privateKey,encode));
        //使用私钥加密
        String encode1 = encodeRSA(algorithm, privateKey, input);
        System.out.println("私钥加密后 = " + encode1);
        //使用公钥解密
        System.out.println("公钥解密 = " + decodeRSA(algorithm,publicKey,encode1));
    }

    /**
     * 解密
     * @param algorithm 非对称加密算法
     * @param decodeKey 解密key
     * @param data 密文
     * @return
     * @throws Exception
     */
    public static String decodeRSA(String algorithm,Key decodeKey,String data) throws Exception{
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.DECRYPT_MODE,decodeKey);
        byte[] bytes = cipher.doFinal(Base64.decode(data));
        return new String(bytes);
    }

    /**
     * 加密
     * @param algorithm 非对称加密算法
     * @param encodeKey 加密key
     * @param data 明文
     * @return
     * @throws Exception
     */
    public static String encodeRSA(String algorithm, Key encodeKey,String data) throws Exception {
        //创建加密对象
        Cipher cipher = Cipher.getInstance(algorithm);
        //对加密对象进行初始化
        //参数一：加密的模式，加密还是解密
        //参数二：你想使用公钥加密还是私钥加密
        cipher.init(Cipher.ENCRYPT_MODE, encodeKey);
        //使用公钥进行加密
        byte[] bytes = cipher.doFinal(data.getBytes());
        return Base64.encode(bytes);
    }

    /**
     * 读取公钥文件中的密钥
     * @param pubPath 公钥路径
     * @param algorithm 非对称加密算法
     * @return
     * @throws Exception
     */
    public static PublicKey getPublicKey(String pubPath,String algorithm) throws Exception {
        //读取公钥字符串
        String publicKeyString = FileUtils.readFileToString(new File(pubPath), StandardCharsets.UTF_8);
        //创建key的工厂
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        //创建公钥key的规则
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decode(publicKeyString));
        //返回公钥key
        return keyFactory.generatePublic(keySpec);
    }

    /**
     * 读取私钥文件中的密钥
     * @param priPath 私钥路径
     * @param algorithm 非对称加密算法
     * @return
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String priPath,String algorithm) throws Exception {
        //读取私钥字符串
        String privateKeyString = FileUtils.readFileToString(new File(priPath), StandardCharsets.UTF_8);
        //创建Key的工厂
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        //创建私钥key的规则
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decode(privateKeyString));
        //返回私钥对象
        return keyFactory.generatePrivate(keySpec);
    }

    /**
     * 生成公钥私钥文件
     * @param algorithm 非对称加密算法
     * @param pubPath 公钥路径
     * @param priPath 私钥路径
     */
    public static void generateKeyToFile(String algorithm, String pubPath, String priPath) {
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            PrivateKey privateKey = keyPair.getPrivate();
            PublicKey publicKey = keyPair.getPublic();
            String privateEncode = Base64.encode(privateKey.getEncoded());
            String publicEncode = Base64.encode(publicKey.getEncoded());
            //把公钥和私钥保存到根目录
            FileUtils.writeStringToFile(new File(pubPath),publicEncode, StandardCharsets.UTF_8);
            FileUtils.writeStringToFile(new File(priPath),privateEncode, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
